package fr.miage.orleans.aar.ejb.administration;

import fr.miage.orleans.aar.ejb.FacadeGettersBean;
import fr.miage.orleans.aar.ejb.FacadeUtils;
import fr.miage.orleans.aar.modele.Administrateur;
import fr.miage.orleans.aar.modele.Arbitre;
import fr.miage.orleans.aar.modele.ButMatch;
import fr.miage.orleans.aar.modele.ButTirAuBut;
import fr.miage.orleans.aar.modele.Equipe;
import fr.miage.orleans.aar.modele.EquipeTournoi;
import fr.miage.orleans.aar.modele.EtatMatchTour;
import fr.miage.orleans.aar.modele.EtatTournoi;
import fr.miage.orleans.aar.modele.Joueur;
import fr.miage.orleans.aar.modele.MatchTour;
import fr.miage.orleans.aar.modele.Tournoi;
import fr.miage.orleans.aar.modele.valueobject.ValueObjectButTirAuBut;
import fr.miage.orleans.aar.modele.valueobject.ValueObjectMatch;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author Steve Cancès <steve.cances@gmail.com>
 */
@Stateless
@LocalBean
public class FacadeAdministrationBean implements FacadeAdministrationLocal {

	@PersistenceContext(unitName = FacadeUtils.PERSISTENCE_CONTEXT_UNIT_NAME)
	private EntityManager entityManager;

	@EJB
	private FacadeGettersBean facadeGetters;

	/*
     @Override
     public PosteJoueur creerPosteJoueur(String nomPoste) {
     if (nomPoste != null && !nomPoste.isEmpty()) {
     PosteJoueur posteJoueur = new PosteJoueur();
     posteJoueur.setNomPoste(nomPoste);
     this.entityManager.persist(posteJoueur);
     return posteJoueur;
     }
     return null;
     }
	 */
	@Override
	public Arbitre creerArbitre(String nom, String prenom) {
		Arbitre arbitre = null;
		if (nom != null && !nom.isEmpty() && prenom != null && !prenom.isEmpty()) {
			arbitre = new Arbitre();
			arbitre.setNom(nom);
			arbitre.setPrenom(prenom);
			this.entityManager.persist(arbitre);
		}
		return arbitre;
	}

	@Override
	public boolean creerNouveauTournoi(String nomTournoi) {
		if (nomTournoi != null && !nomTournoi.isEmpty()) {
			Tournoi tournoi = new Tournoi();
			tournoi.setNomTournoi(nomTournoi);
			tournoi.setEtatTournoi(EtatTournoi.EN_PREPARATION);
			try {
				this.entityManager.persist(tournoi);
				this.entityManager.flush();
			} catch (Exception ex) {
				return false;
			}
			return true;
		} else {
			return false;
		}
	}

	@Override
	public boolean validerPreparationTournoi(int tournoiId) {
		Tournoi tournoi = this.facadeGetters.getTournoiById(tournoiId);
		if (tournoi != null && tournoi.getEtatTournoi() == EtatTournoi.EN_PREPARATION && tournoi.nombreEquipesPuissanceDe2()) {
			tournoi.setEtatTournoi(EtatTournoi.EN_COURS);
			Collection<EquipeTournoi> equipeTournois = tournoi.getEquipesTournoi();
			Collections.shuffle((List<?>) equipeTournois);
			AtomicInteger numeroEquipe = new AtomicInteger();
			MatchTour matchTourTmp = null;
			AtomicInteger numeroMatch = new AtomicInteger();
			// Pour toutes les equipes
			for (EquipeTournoi equipeTournoi : equipeTournois) {
				// Le numero de l'equipe courante
				int numEquipeCourant = numeroEquipe.incrementAndGet();
				equipeTournoi.setNumeroEquipe(numEquipeCourant);
				//Les equipes de numero impaire
				if (numEquipeCourant % 2 == 1) {
					matchTourTmp = new MatchTour();
					matchTourTmp.setTournoi(tournoi);
					tournoi.getMatchs().add(matchTourTmp);
					matchTourTmp.setEtatMatch(EtatMatchTour.NON_COMMENCE);
					matchTourTmp.setEquipeA(equipeTournoi.getEquipe());
					equipeTournoi.getEquipe().getMatchToursA().add(matchTourTmp);
					matchTourTmp.setNumeroMatch(numeroMatch.incrementAndGet());
				} else {
					if (matchTourTmp != null) {
						matchTourTmp.setEquipeB(equipeTournoi.getEquipe());
						equipeTournoi.getEquipe().getMatchToursB().add(matchTourTmp);
					}
				}
			}
			this.entityManager.flush();
			return true;
		}
		return false;
	}

	@Override
	public boolean desinscrireEquipeTournoi(int tournoiId, int equipeId) {
		EquipeTournoi equipeTournoi = this.facadeGetters.getEquipeTournoiById(tournoiId, equipeId);
		Tournoi tournoi = equipeTournoi.getTournoi();
		tournoi.getEquipesTournoi().remove(equipeTournoi);
		Equipe equipe = equipeTournoi.getEquipe();
		equipe.getEquipesTournoi().remove(equipeTournoi);
		try {
			this.entityManager.remove(equipeTournoi);
			this.entityManager.flush();
		} catch (Exception ex) {
			return false;
		}
		return true;
	}

	@Override
	public Collection<Arbitre> getAllArbitres() {
		Collection<Arbitre> returnvalue = null;
		Query query = entityManager.createQuery("From Arbitre a");
		try {
			returnvalue = query.getResultList();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		return returnvalue;
	}

	@Override
	public ButMatch addButMatch(int idMatch, int idEquipe, int idJoueur, int minute) {
		ButMatch but = null;
		MatchTour matchTour = this.facadeGetters.getMatchTourById(idMatch);
		Equipe equipe = this.facadeGetters.getEquipeById(idEquipe);
		Joueur joueur = this.facadeGetters.getJoueurById(idJoueur);
		if (matchTour != null && equipe != null && joueur != null) {
			if (equipe.getJoueurs().contains(joueur)) {
				if (matchTour.getEquipeA().equals(equipe) || matchTour.getEquipeB().equals(equipe)) {
					EtatMatchTour etatMatch = matchTour.getEtatMatch();
					if (etatMatch == EtatMatchTour.PREMIERE_MI_TEMPS || etatMatch == EtatMatchTour.DEUXIEME_MI_TEMPS || etatMatch == EtatMatchTour.PROLONGATION_PREMIERE_MI_TEMPS || etatMatch == EtatMatchTour.PROLONGATION_DEUXIEME_MI_TEMPS) {
						but = new ButMatch();
						but.setMatch(matchTour);
						but.setEquipe(equipe);
						but.setJoueur(joueur);
						but.setMinuteBut(minute);
						this.entityManager.persist(but);
					}
				}
			}
		}
		return but;
	}

	@Override
	public Collection<Administrateur> getAllAdmins() {
		Collection<Administrateur> returnvalue = null;
		Query query = entityManager.createQuery("FROM Administrateur a");
		try {
			returnvalue = query.getResultList();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		return returnvalue;
	}

	@Override
	public boolean commencerPremiereMiTemps(int idMatch) {
		boolean ok = true;
		MatchTour matchTour = this.facadeGetters.getMatchTourById(idMatch);
		if (matchTour != null && matchTour.getEtatMatch() == EtatMatchTour.NON_COMMENCE && matchTour.getArbitre() != null && matchTour.getEquipeA() != null && matchTour.getEquipeB() != null) {
			try {
				matchTour.setEtatMatch(EtatMatchTour.PREMIERE_MI_TEMPS);
				this.entityManager.flush();
			} catch (Exception e) {
				ok = false;
			}
		} else {
			ok = false;
		}
		return ok;
	}

	@Override
	public boolean terminerPeriode(int idMatch) {
		boolean ok = true;
		MatchTour matchTour = this.facadeGetters.getMatchTourById(idMatch);
		ValueObjectMatch voMatch = new ValueObjectMatch(matchTour);
		if (matchTour != null) {
			switch (matchTour.getEtatMatch()) {
			case PREMIERE_MI_TEMPS: {
				matchTour.setEtatMatch(EtatMatchTour.DEUXIEME_MI_TEMPS);
				break;
			}
			case DEUXIEME_MI_TEMPS: {
				if (voMatch.getScoreA() > voMatch.getScoreB()) {
					matchTour.setEtatMatch(EtatMatchTour.TERMINE_A_GAGNE);
				} else {
					if (voMatch.getScoreA() < voMatch.getScoreB()) {
						matchTour.setEtatMatch(EtatMatchTour.TERMINE_B_GAGNE);
					} else {
						matchTour.setEtatMatch(EtatMatchTour.PROLONGATION_PREMIERE_MI_TEMPS);
					}
				}
				break;
			}
			case PROLONGATION_PREMIERE_MI_TEMPS: {
				matchTour.setEtatMatch(EtatMatchTour.PROLONGATION_DEUXIEME_MI_TEMPS);
				break;
			}
			case PROLONGATION_DEUXIEME_MI_TEMPS: {
				if (voMatch.getScoreA() > voMatch.getScoreB()) {
					matchTour.setEtatMatch(EtatMatchTour.TERMINE_A_GAGNE);
				} else {
					if (voMatch.getScoreA() < voMatch.getScoreB()) {
						matchTour.setEtatMatch(EtatMatchTour.TERMINE_B_GAGNE);
					} else {
						matchTour.setEtatMatch(EtatMatchTour.TIR_AU_BUT);
					}
				}
				break;
			}
			case TIR_AU_BUT:{
				int nbButEquipeA = 0;
				int nbButEquipeB = 0;
				for(ValueObjectButTirAuBut vob : voMatch.getListTOB()){
					if(vob.isReussi() && vob.getEquipe().getId()==voMatch.getEquipeA().getId())
						nbButEquipeA++;
					if(vob.isReussi() && vob.getEquipe().getId()==voMatch.getEquipeB().getId())
					nbButEquipeB++;
				}
				if (nbButEquipeA > nbButEquipeB){
					matchTour.setEtatMatch(EtatMatchTour.TERMINE_A_GAGNE);
				}else{
					if(nbButEquipeB > nbButEquipeA){
						matchTour.setEtatMatch(EtatMatchTour.TERMINE_B_GAGNE);
					}else{
						matchTour.setEtatMatch(EtatMatchTour.MORT_SUBITE);
					}
				}
				break;
			}
			case MORT_SUBITE : 
			{
				int nbButEquipeA = 0;
				int nbButEquipeB = 0;
				for(ValueObjectButTirAuBut vob : voMatch.getListTOB()){
					if(vob.isReussi() && vob.getEquipe().getId()==voMatch.getEquipeA().getId())
						nbButEquipeA++;
					if(vob.isReussi() && vob.getEquipe().getId()==voMatch.getEquipeB().getId())
					nbButEquipeB++;
				}
				if (nbButEquipeA > nbButEquipeB)
				{
					matchTour.setEtatMatch(EtatMatchTour.TERMINE_A_GAGNE);
				}
				else
				{
					if(nbButEquipeB > nbButEquipeA)
					{
						matchTour.setEtatMatch(EtatMatchTour.TERMINE_B_GAGNE);
					}
					else
					{
						System.out.println("I SHOULDNT BE THERE...");
					}
				}
				break;
			}
			default: {
				ok = false;
			}
			}
			if (matchTour.getEtatMatch() == EtatMatchTour.TERMINE_A_GAGNE || matchTour.getEtatMatch() == EtatMatchTour.TERMINE_B_GAGNE) {
				this.terminerMatch(matchTour.getMatchTourId());
			}
			//this.entityManager.flush();
		} else {
			ok = false;
		}
		return ok;
	}

	public void terminerMatch(int idMatch) {
		MatchTour matchTour = this.facadeGetters.getMatchTourById(idMatch);
		if (matchTour != null) {
			EtatMatchTour emt = matchTour.getEtatMatch();
			Tournoi tournoi = matchTour.getTournoi();
			ValueObjectMatch valueObjectMatch = new ValueObjectMatch(matchTour);
			// Si ce n'est pas la finale
			if (Math.pow(2, valueObjectMatch.getRangMatch()) < tournoi.getEquipesTournoi().size()) {
				// Si le match est en etat termine et que le match enfant n'a pas encore été set
				if (matchTour.getMatchEnfant() == null && (emt == EtatMatchTour.TERMINE_A_GAGNE || emt == EtatMatchTour.TERMINE_B_GAGNE)) {
					MatchTour matchTourFrere = this.facadeGetters.getMatchTourFrereById(matchTour.getMatchTourId());
					Equipe equipeGagnante;
					if (emt == EtatMatchTour.TERMINE_A_GAGNE) {
						equipeGagnante = matchTour.getEquipeA();
					} else {
						equipeGagnante = matchTour.getEquipeB();
					}
					MatchTour matchTourEnfant;
					if (matchTourFrere == null || matchTourFrere.getMatchEnfant() == null) {
						matchTourEnfant = new MatchTour();
						matchTourEnfant.setTournoi(tournoi);
						matchTourEnfant.setEtatMatch(EtatMatchTour.NON_COMMENCE);

						matchTourEnfant.setEquipeA(equipeGagnante);
						this.entityManager.persist(matchTourEnfant);

						//TODO a modifier


						ValueObjectMatch voMatch = new ValueObjectMatch(matchTour);
						List<Integer> listeNumMatch = new ArrayList<>();
						int _num = 1;
						int nbMatch = matchTour.getTournoi().getEquipesTournoi().size();
						int rang=  voMatch.getRangMatch();
						int inc = (int) Math.pow(2, rang-1);
						for(int j = 0 ; j < rang ; ++j)
						{
							nbMatch = nbMatch /2;
						}
						for(int  i = 0 ; i <nbMatch ; i++)
						{
							listeNumMatch.add(_num);
							_num+=inc;
						}
						int numeroMatchEnfant = 0;
						for(int i = 0 ; i < listeNumMatch.size() ; ++i)
						{
							if(listeNumMatch.get(i) == matchTour.getNumeroMatch())
							{
								if(i%2 == 0)
								{
									numeroMatchEnfant = listeNumMatch.get(i);
								}
								else
								{
									numeroMatchEnfant = listeNumMatch.get(i-1);
								}
							}
						}
						matchTourEnfant.setNumeroMatch(numeroMatchEnfant);

					} else {
						matchTourEnfant = matchTourFrere.getMatchEnfant();
						matchTourEnfant.setEquipeB(equipeGagnante);
					}
					matchTour.setMatchEnfant(matchTourEnfant);
				}
			} else {
				tournoi.setEtatTournoi(EtatTournoi.TERMINE);
			}
		}
	}

	@Override
	public MatchTour affecterArbitreMatch(int idMatch, int idArbitre) {
		MatchTour matchTour = this.facadeGetters.getMatchTourById(idMatch);
		Arbitre arbitre = this.facadeGetters.getArbitreById(idArbitre);
		matchTour.setArbitre(arbitre);
		try {
			this.entityManager.flush();
			matchTour = this.entityManager.merge(matchTour);
		} catch (Exception ex) {

		}
		return matchTour;
	}

	@Override
	public Administrateur logIn(String login, String password) {
		Administrateur administrateur = null;
		Collection<Administrateur> administrateurs;
		Query query = entityManager.createQuery("FROM Administrateur a WHERE a.login=:login AND a.password=:password");
		query.setParameter("login", login);
		query.setParameter("password", password);
		try {
			administrateurs = query.getResultList();
			if (!administrateurs.isEmpty()) {
				Administrateur[] administrateursArray = new Administrateur[administrateurs.size()];
				administrateursArray = (Administrateur[]) administrateurs.toArray(administrateursArray);
				administrateur = administrateursArray[0];
			}
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		return administrateur;
	}

	
	
	@Override
	public ButTirAuBut addTirAuBut(int idMatch, int idEquipe, int idJoueur,	boolean reussite) {
		ButTirAuBut but = null;
		MatchTour matchTour = this.facadeGetters.getMatchTourById(idMatch);
		System.out.println("FacadeAdmin : size TOB" + matchTour.getButsTirAuBut().size());
		boolean isEquipeA = (matchTour.getButsTirAuBut().size() % 2) == 0;
		int rang = (matchTour.getButsTirAuBut().size()/2) + 1 ;
		Equipe equipe = this.facadeGetters.getEquipeById(idEquipe);
		Joueur joueur = this.facadeGetters.getJoueurById(idJoueur);
		if (matchTour != null && equipe != null && joueur != null) {
			if (equipe.getJoueurs().contains(joueur)) {
				if (matchTour.getEquipeA().equals(equipe) || matchTour.getEquipeB().equals(equipe)) {
					EtatMatchTour etatMatch = matchTour.getEtatMatch();
					if (etatMatch == EtatMatchTour.TIR_AU_BUT || etatMatch == EtatMatchTour.MORT_SUBITE) {
						System.out.println("J'ajoute le but");
						but = new ButTirAuBut();
						but.setMatch(matchTour);
						but.setEquipe(equipe);
						but.setJoueur(joueur);
						but.setRang(rang);
						but.setReussi(reussite);
						this.entityManager.persist(but);
						matchTour.getButs().add(but);
					}
				}
			}
		}
				
		if(matchTour.getButsTirAuBut().size() == 10)
		{
			terminerPeriode(idMatch);
		}
		else
		{
			int equipeASuccess = 0;
			int equipeBSuccess = 0;
			for(ButTirAuBut aBut : matchTour.getButsTirAuBut())
			{
				if(aBut.isReussi())
				{
					if(aBut.getEquipe().getEquipeId() == matchTour.getEquipeA().getEquipeId())
					{
						equipeASuccess++;
					}
					else
					{
						equipeBSuccess++;
					}
				}
			}
			
			if((matchTour.getEtatMatch() != EtatMatchTour.MORT_SUBITE))
			{
				int restantB = 5-rang +1;
				int restantA = restantB -1;
				if(!isEquipeA)
					restantB--;
				if(equipeASuccess > equipeBSuccess)
				{
					if((equipeASuccess - equipeBSuccess) > restantB)
					{
						System.out.println("Je termine le match");
						terminerPeriode(idMatch);
					}
				}
				else
				{
					if(equipeBSuccess > equipeASuccess)
					{
						if((equipeBSuccess - equipeASuccess) > restantA)
						{
							System.out.println("Je termine le match");
							terminerPeriode(idMatch);
						}
					}
				}
/*				
				
				if(isEquipeA)
				{

					System.out.println("C'est A qui a tiré , il en reste " + restantB + " pour B et " + restantA + " pour A");
					System.out.println("A en a marqué " + equipeASuccess + " et B " + equipeBSuccess);
				}
				else
				{
					System.out.println("C'est B qui a tiré , il en reste " + restantA + " pour A et "+ restantB + " pour B");
					System.out.println("A en a marqué " + equipeASuccess + " et B " + equipeBSuccess);
				}*/
			}
			else
			{
				if(!isEquipeA)
				{
					if(equipeASuccess != equipeBSuccess)
					{
						terminerPeriode(idMatch);
					}
				}
			}
		}
		return but;
	}
}
